package com.dkts.oil.test;

import com.dkts.oil.mysql.entity.AisPoint;

import java.math.BigDecimal;
import java.util.*;

/**
 * 轨迹分段处理：根据时间和空间阈值将每个 MMSI 的轨迹点分成多个段
 */
public class GeoJsonExporterV2分段处理 {

    // 分段时长阈值：120 分钟（秒）
    private static final long SEGMENT_TIME_GAP = 120 * 60;
    // 分段空间阈值：0.27° ≈ 30 公里
    private static final double SEGMENT_DISTANCE_THRESHOLD = 30;

    public static void main(String[] args) throws Exception {
        String uuid=UUID.randomUUID().toString();
        // 从前置流程获取去重、排序后的 AIS 点
        Map<String, List<AisPoint>> aisPointsByMmsi = GeoJsonExporterV2去重和时间排序.getAisPointsByMmsi(ParentTest.inputCsvPath, ParentTest.outputDir,uuid);

        // 进行分段处理
        Map<String, List<List<AisPoint>>> segmented = segmentAisPoints(aisPointsByMmsi,uuid);

        // 打印分段结果摘要
        for (Map.Entry<String, List<List<AisPoint>>> entry : segmented.entrySet()) {
            String mmsi = entry.getKey();
            List<List<AisPoint>> segments = entry.getValue();
            System.out.printf("MMSI=%s 共分段=%d\n", mmsi, segments.size());
            for (int i = 0; i < segments.size(); i++) {
                List<AisPoint> seg = segments.get(i);
                Date start = seg.get(0).getTime();
                Date end = seg.get(seg.size() - 1).getTime();
                System.out.printf("  段 %d: 点数=%d, 起=%s, 止=%s\n", i + 1, seg.size(), start, end);
            }
            System.out.println();
        }
    }

    /**
     * 对每个 MMSI 的轨迹点列表，根据时间和空间阈值进行分段
     * @param aisPointsByMmsi 按 MMSI 分组的轨迹点列表
     * @return Map<MMSI, List<Segments>>，每个 MMSI 对应的分段列表
     */
    public static Map<String, List<List<AisPoint>>> segmentAisPoints(Map<String, List<AisPoint>> aisPointsByMmsi,String uuid) {
        Map<String, List<List<AisPoint>>> result = new HashMap<>();
        for (Map.Entry<String, List<AisPoint>> entry : aisPointsByMmsi.entrySet()) {
            String mmsi = entry.getKey();
            List<AisPoint> points = entry.getValue();
            // 确保按时间排序
            points.sort(Comparator.comparing(AisPoint::getTime));

            List<List<AisPoint>> segments = new ArrayList<>();
            List<AisPoint> current = new ArrayList<>();
            if (!points.isEmpty()) {
                current.add(points.get(0));
                for (int i = 1; i < points.size(); i++) {
                    AisPoint prev = points.get(i - 1);
                    AisPoint now = points.get(i);
                    Long timeGap = (now.getTime().getTime() - prev.getTime().getTime()) / 1000;

                    long minutes = timeGap / 60;
                    long seconds = timeGap % 60;

                    Double timeInterval = Double.valueOf(minutes + "." + seconds);

                    double dist = calculateDistanceKm(prev.getLat(), prev.getLon(), now.getLat(), now.getLon());
                    now.setTimeInterval( new BigDecimal(timeInterval).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue());
                    // 如果超出时间或空间阈值，则开启新段
                    if (timeGap > SEGMENT_TIME_GAP && dist > SEGMENT_DISTANCE_THRESHOLD) {
                        System.out.println("开启新段 "+  mmsi + " 时间间隔："+ now.getTimeInterval()+"分， 距离："+dist+"公里");
                        segments.add(current);
                        current = new ArrayList<>();
                    }
                    now.setDistance(dist);

                    current.add(now);
                }
                if (!current.isEmpty()) {
                    segments.add(current);
                }
            }
            result.put(mmsi, segments);
        }
        return result;
    }

    /**
     * 计算两点间球面距离，返回公里
     */
    /**
     * 计算两点间球面距离，返回公里（保留两位小数）
     */
    private static double calculateDistanceKm(double lat1, double lon1, double lat2, double lon2) {
        final double R = 6371.0; // 地球半径，单位：公里
        double dLat = Math.toRadians(lat2 - lat1);
        double dLon = Math.toRadians(lon2 - lon1);
        double a = Math.sin(dLat / 2) * Math.sin(dLat / 2)
                + Math.cos(Math.toRadians(lat1)) * Math.cos(Math.toRadians(lat2))
                * Math.sin(dLon / 2) * Math.sin(dLon / 2);
        double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
        double distance = R * c;
        // 保留两位小数
        return Math.round(distance * 100) / 100.0;
    }
}
